package com.ruoyi.spin.task;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpStatus;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.google.common.base.Stopwatch;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.DingUtil;
import com.ruoyi.spin.domain.SpinCoinBean;
import com.ruoyi.spin.domain.Task;
import com.ruoyi.spin.domain.req.SpinLinkV2ReqDTO;
import com.ruoyi.spin.domain.resp.SpinCoinRspDTO;
import com.ruoyi.spin.enums.SpinEnums;
import com.ruoyi.spin.service.ISpinCoinBeanService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.TimeUnit;

/**
 * spinlink任务
 *
 * @author lorry
 * @date 2023-1-13 17:43:37
 */
@Component("spinLinkBTask")
@Slf4j
public class SpinLinkBetaTask {
  public static final String ORIGIN_DATE_PATTERN = "MM-dd-yyyy";
  public static final String DATE_PATTERN = "yyyy-MM-dd";
  private static final Map<String, String> HEADER_MAP = new HashMap<>(8);

  static {
    HEADER_MAP.put(
        "Accept",
        "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9");
    HEADER_MAP.put("Accept-Encoding", "gzip, deflate");
    HEADER_MAP.put("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");
    HEADER_MAP.put("Cache-Control", "max-age=0");
    HEADER_MAP.put("Connection", "keep-alive");
    HEADER_MAP.put(
        "User-Agent",
        "Mozilla/5.0 (Linux; Android 9; SM-A105M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Mobile Safari/537.36");
  }

  String fetchCoinUrl = "http://128.199.174.32/api/coins";
  String fetchSpinUrl = "http://128.199.174.32/api/spins";
  @Autowired private RuoYiConfig ruoYiConfig;
  @Autowired private ISpinCoinBeanService spinCoinBeanService;

  /**
   * 定时任务，每3小时执行一次
   *
   * @param start
   * @param bound
   * @throws InterruptedException
   */
  public void delayFetchCoin(Integer start, Integer bound) throws InterruptedException {
    Stopwatch started = Stopwatch.createStarted();
    log.info("delayFetchCoin start...");
    if (CollectionUtils.isEmpty(ruoYiConfig.getPostUrls())) {
      return;
    }

    int round = new Random().nextInt(bound);
    int execTime = start + round;
    log.info("delayFetchCoin execTime: {} start: {} round: {}", execTime, start, round);

    Calendar calendar = Calendar.getInstance();
    calendar.add(Calendar.SECOND, execTime);
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String date = format.format(calendar.getTime());
    String name = StrUtil.format("fetch1#{}", date);
    log.info("delayFetchCoin fetch任务执行时间：{}，任务名：{}", date, name);

    Task task = new Task(name, execTime, TimeUnit.SECONDS);
    DelayQueue<Task> delayQueue = new DelayQueue<>();
    delayQueue.put(task);

    while (delayQueue.size() != 0) {
      Task t = delayQueue.poll();

      if (t != null) {
        log.info("delayFetchCoin fetch1任务：{} 执行时间：{}", t.name, DateUtil.now());
        crawler(fetchCoinUrl);
      }
      Thread.sleep(1000);
    }
    log.info("delayFetchCoin elapsed time: {}", started.elapsed(TimeUnit.MILLISECONDS));
  }

  public void delayFetchSpin(Integer start, Integer bound) throws InterruptedException {
    Stopwatch started = Stopwatch.createStarted();
    log.info("delayFetchSpin start...");
    if (CollectionUtils.isEmpty(ruoYiConfig.getPostUrls())) {
      return;
    }

    int round = new Random().nextInt(bound);
    int execTime = start + round;
    log.info("delayFetchSpin execTime: {} start: {} round: {}", execTime, start, round);

    Calendar calendar = Calendar.getInstance();
    calendar.add(Calendar.SECOND, execTime);
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String date = format.format(calendar.getTime());
    String name = StrUtil.format("fetch1#{}", date);
    log.info("delayFetchSpin fetch任务执行时间：{}，任务名：{}", date, name);

    Task task = new Task(name, execTime, TimeUnit.SECONDS);
    DelayQueue<Task> delayQueue = new DelayQueue<>();
    delayQueue.put(task);

    while (delayQueue.size() != 0) {
      Task t = delayQueue.poll();

      if (t != null) {
        log.info("delayFetchSpin fetch1任务：{} 执行时间：{}", t.name, DateUtil.now());
        crawler(fetchSpinUrl);
      }
      Thread.sleep(1000);
    }
    log.info("delayFetchSpin elapsed time: {}", started.elapsed(TimeUnit.MILLISECONDS));
  }

  /** 抓取方法1 http://128.199.255.88/api/get-spins http://128.199.255.88/api/get-coins */
  public void crawler(String url) {
    Stopwatch stopwatch = Stopwatch.createStarted();
    log.info("crawler start...");

    HttpRequest request = HttpRequest.get(url);
    request.addHeaders(HEADER_MAP);
    HttpResponse response = request.execute();

    if (response.getStatus() == HttpStatus.HTTP_OK) {
      String body = response.body();
      log.info("crawler result: {}", JSONUtil.toJsonStr(body));
      SpinCoinRspDTO spinCoinRspDTO = JSONUtil.toBean(body, SpinCoinRspDTO.class);
      List<SpinCoinRspDTO.DataDTO> data = spinCoinRspDTO.getData();

      List<SpinLinkV2ReqDTO> reqDTOList = new ArrayList<>();
      List<SpinCoinBean> spinCoinBeans = new ArrayList<>();

      for (SpinCoinRspDTO.DataDTO datum : data) {
        SpinLinkV2ReqDTO reqDTO = new SpinLinkV2ReqDTO();
        reqDTO.setId(datum.getId());
        reqDTO.setState(0);
        reqDTO.setVersion(0);
        reqDTO.setSource(SpinEnums.SourceTypeEnum.GET_COIN_SPIN.type);
        reqDTO.setSpinNumber(datum.getSpinNumber());
        reqDTO.setCoinNumber(Float.valueOf(datum.getCoinNumber()));
        reqDTO.setToken(datum.getToken());
        String wwwUrl = "https://static.moonactive.net/static/coinmaster/reward/reward2.html?c=";
        String link = StrUtil.format("{}{}", wwwUrl, datum.getToken());
        reqDTO.setLink(link);

        Float coins = Float.valueOf(datum.getCoinNumber());
        Integer spins = datum.getSpinNumber();
        int stype = 3;
        String title = "25 Free spins";
        if (coins > 0 && spins > 0) {
          title =
              StrUtil.format(
                  "{} Spins & {} Million Coins", spins, coins.toString().replace(".0", ""));
        } else if (coins > 0) {
          stype = 1;
          title = StrUtil.format("{} Million Coins", coins.toString().replace(".0", ""));
        } else if (spins > 0) {
          stype = 2;
          title = StrUtil.format("{} Free Spins", spins);
        }
        reqDTO.setStype(stype);
        reqDTO.setTitle(title);

        String createdDate =
            DateUtils.convertPattern(datum.getCreatedTime(), ORIGIN_DATE_PATTERN, DATE_PATTERN);
        reqDTO.setCreatedTime(createdDate);

        if (!StrUtil.isAllNotBlank(
            reqDTO.getLink(),
            reqDTO.getTitle(),
            reqDTO.getToken(),
            reqDTO.getCreatedTime(),
            String.valueOf(reqDTO.getStype()))) {
          log.error("fetch1 some field error {}", JSONUtil.toJsonStr(reqDTO));
        } else {
          reqDTOList.add(reqDTO);

          SpinCoinBean spinCoinBean = BeanUtil.copyProperties(datum, SpinCoinBean.class);
          spinCoinBean.setCreatedTime(createdDate);
          spinCoinBean.setInsertedTime(new Date());
          spinCoinBeans.add(spinCoinBean);
        }
      }

      if (!CollectionUtils.isEmpty(spinCoinBeans)) {
        spinCoinBeans.forEach(
            a -> {
              try {
                spinCoinBeanService.insertSpinCoinBean(a);
              } catch (Exception e) {
                if (!e.getMessage().contains("Duplicate entry")) {
                  log.error("插入失败!", e);
                }
              }
            });
      } else {
        DingUtil.sendText("没有抓到数据，请检查！！！");
      }

      if (!CollectionUtils.isEmpty(reqDTOList)) {
        for (int i = 0; i < ruoYiConfig.getPostUrls().size(); i++) {
          String result =
              HttpUtil.post(ruoYiConfig.getPostUrls().get(i), JSONUtil.toJsonStr(reqDTOList));
          log.info("crawler post spin{} result: {}", i + 1, result);
        }
      }
    }

    log.info("crawler end, elapsed time: {}", stopwatch.elapsed(TimeUnit.MILLISECONDS));
  }
}
